#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

from heat.common import exception
from heat.engine import clients
from heat.engine import constraints
from heat.engine import properties
from heat.engine import resource
from heat.engine.resources.vpc import VPC
from heat.openstack.common import excutils
from heat.openstack.common.gettextutils import _
from heat.openstack.common import log as logging

from heat.engine.resources.qingresources import qing_utils
from heat.engine.resources.qingresources import qing_cfg

logger = logging.getLogger(__name__)


#TBD:  
# Eip brandwidth shoud be set by user

class ElasticIp(resource.Resource):
    PROPERTIES = (
        DOMAIN, INSTANCE_ID,
    ) = (
        'Domain', 'InstanceId',
    )

    properties_schema = {
        DOMAIN: properties.Schema(
            properties.Schema.STRING,
            _('Set to "vpc" to have IP address allocation associated to your '
              'VPC.'),
            constraints=[
                constraints.AllowedValues(['vpc']),
            ]
        ),
        INSTANCE_ID: properties.Schema(
            properties.Schema.STRING,
            _('Instance ID to associate with EIP.')
        ),
    }

    attributes_schema = {
        'AllocationId': _('ID that Qing assigns to represent the allocation of'
                          ' the address for use with Qingcloud VPC. Returned only'
                          ' for VPC elastic IP addresses.'),
        'IPAddrress': _('IP address of the eip')
    }

    def __init__(self, name, json_snippet, stack):
        super(ElasticIp, self).__init__(name, json_snippet, stack)
        self.ipaddress = None


    def handle_create(self):
        """Allocate a floating IP for the current tenant."""
        ips = None

        iaas = qing_utils.CloudIaas()
        rets = iaas.allocate_eips(bandwidth = 2)
        if rets[0] != 0:
            logger.error(_('ElasticIP create failed'))
            return

        print(rets[1])
        self.resource_id_set(rets[1][0])
        rets = iaas.list_eips([self.resource_id])
        if rets[0] != 0:
            logger.error(_('ElasticIP create failed'))
            return
        
        self.ipaddress = rets[1][0]['eip_id']   
        logger.info(_('ElasticIP create id %s with ip: %s') %(self.resource_id, self.ipaddress))     

        domain_id = self.properties[self.DOMAIN]
        if domain_id:
            rets = iaas.associate_eip(self.resource_id, domain_id)
            if rets[0] != 0:
                raise exception(_('associate eip to vpc failed'))
                return
            logger.info(_('create eip success'))
            return

        instance_id = self.properties[self.INSTANCE_ID]
        if instance_id:
            rets = iaas.associate_eip(self.resource_id, instance_id)
            if rets[0] != 0:
                logger.error(_('ElasticIP associate to instance failed'))
                return
            return

    def handle_delete(self):
        iaas = qing_utils.CloudIaas()
        rets = iaas.dissociate_eips([self.resource_id])
        if rets[0] != 0:
            logger.error(_('Dissociate eip failed'))
            return
        
        """De-allocate a floating IP."""
        if self.resource_id is not None:
            rets = iaas.release_eips([self.resource_id])
            if rets[0] != 0:
                raise exception(_('delete eip failed, %s') %self.resource_id)
                return
            logger.info(_('delete eip success %s') %self.resource_id)

    def FnGetRefId(self):
        return unicode(self.ipaddress)

    def _resolve_attribute(self, name):
        if name == 'AllocationId':
            return unicode(self.resource_id)
        elif name == 'IPAddress':
            return unicode(self.ipaddress)


class ElasticIpAssociation(resource.Resource):
    '''
    in qingcloud, we can associate eip with router or instance
    '''
    PROPERTIES = (
        INSTANCE_ID, EIP, VPC_ID,
    ) = (
        'InstanceId', 'EIP', 'VpcId', 
    )

    properties_schema = {
        INSTANCE_ID: properties.Schema(
            properties.Schema.STRING,
            _('Instance ID to associate with EIP specified by EIP property.')
        ),
        EIP: properties.Schema(
            properties.Schema.STRING,
            _('EIP address to associate with instance.')
        ),
        VPC_ID: properties.Schema(
            properties.Schema.STRING,
            _('Allocation ID for VPC EIP address.')
        )
    }

    def FnGetRefId(self):
        return unicode(self.physical_resource_name())

    def handle_create(self):
        print('================================ 10 =======================')
        print(self.properties[self.EIP])
        print(self.properties[self.VPC_ID])
        """Add a floating IP address to a server or router."""
        if self.properties[self.EIP] is None:
            raise exception.error(_('eip is none')) 

        iaas = qing_utils.CloudIaas()
        if self.properties[self.EIP]:
            if self.properties[self.INSTANCE_ID]:
                rets = iaas.associate_eip(self.properties[self.EIP], self.properties[self.INSTANCE_ID])
                if rets[0] != 0:
                    logger.error(_('ElasticIP associate to instance failed'))
                    return
                self.resource_id_set(self.properties[self.EIP])
                logger.debug('ElasticIpAssociation '
                         '%(instance)s.add_floating_ip(%(eip)s)',
                         {'instance': self.properties[self.INSTANCE_ID],
                          'eip': self.properties[self.EIP]})
                print('associate eip success')
            elif self.properties[self.VPC_ID]:
                rets = iaas.change_router_attributes(router=self.properties[self.VPC_ID], eip=self.properties[self.EIP])
                if rets[0] != 0:
                    raise exception.error(_('associate eip to vpc failed'))
                
                #TBD:
                import time
                time.sleep(20)
                rets = iaas.commit_routers([self.properties[self.VPC_ID]])
                if rets[0] != 0:
                    raise exception.error(_('update vpc failed'))
                print('associate eip to vpc success')

    def handle_delete(self):
        """Remove a floating IP address from a server or port."""
        if self.properties[self.EIP]:
            try:
                instance_id = self.properties[self.INSTANCE_ID]
                server = self.nova().servers.get(instance_id)
                if server:
                    server.remove_floating_ip(self.properties[self.EIP])
            except clients.novaclient.exceptions.NotFound:
                pass


def resource_mapping():
    return {
        'Heat::Qing::EIP': ElasticIp,
        'Heat::Qing::EIPAssociation': ElasticIpAssociation,
    }
